﻿#define _CRT_SECURE_NO_WARNINGS
// ↑ 将本行在代码放在第一行可以避免 scanf的报错问题（仅在VS编译器里）

//【入门】3.类和对象(2)
//【入门】4.类和对象(3)



//【头文件包含】
//C++的主要头文件
#include<iostream>//c++的输入输出流
using std::cout, std::endl;

#include<map>
//C的主要头文件
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h> 




//【命名空间】


//【结构体声明】【类声明】
/*学习：结构体的类*/struct ListNode_CPP
{
	int _val;
	ListNode_CPP* _prev;//C++中结构体成员为结构体指针的写法
	struct ListNode_CPP* _next;//也支持C的写法
	struct ListNode_CPP* CreatNode(int val);//还可以定义成员函数
};
/*学习：类的方法和属性*/class Person
{
public:
	void Print()//类的方法：成员函数
	{
		cout << _name << "-" << _age << endl;
	}
	/*void _InfoInput(Person* ip,char* name, int age, char* password)
	{
		ip->_age = age;
		strcpy(ip->_name, name);
		strcpy(ip->_password, password);
	}*/
	void InfoInput(char* name, int age, char* password)
	{
		_age = age;
		strcpy(_name, name);
		strcpy(_password, password);
	}
private:
	char _name[10];//类的属性：成员变量
	int _age;
protected:
	char _password[20];
};
/*学习：类的函数和变量*/class Stack 
{
	//成员函数
public:
	void Init();
	void Push();
	void Pop();
	void Empty();
	//成员变量
private:
	int* _a;
	int _size;
	int _capacity;
protected:
};
/*学习：基本的默认的成员函数*/class DatePra
{
public: 
	///*构造函数*/Date()
	//{
	//	_year =0;_month =1; _day =1;
	//}
	/*1.构造函数*/DatePra(int year=0, int month=1,int day=1)//（全缺省实现不带参调用）
	{
		_year = year;_month = month; _day = day;
		_save = (int*)malloc(sizeof(int) *3);
	}
	/*2.拷贝构造*/DatePra(DatePra&d)//构造函数的另一种重载
	{
		_year =d._year;_month = d._month; _day = d._day;
		_save = (int*)malloc(sizeof(int) * 3);
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
		cout <<"malloc " << _save << endl;
	}
	/*3.析构函数*/~DatePra()
	{
		if (_save!=nullptr)
		{
			free(_save);
			cout << "free " << _save << endl;
			_save = nullptr;
			_year = 0;_month = _day = 1;
		}
	}
	/*4.运算符重载函数 ==*/bool operator==(const DatePra& d)
	{
		return _year == d._year 
			&& _month == d._month 
			&& _day == d._day;
	}
	/*4.运算符重载函数 >*/bool operator>(const DatePra& d)
	{
		return (_year > d._year )||
			(_year >= d._year&& _month > d._month) ||
			(_year >= d._year && _month >= d._month && _day > d._day) ;
	}
	/*4.运算符重载函数 <*/bool operator<(const DatePra& d)
	{
		return (!operator>(d)) && (!operator==(d));
	}
private:
	int _year;
	int _month;
	int _day;
	int* _save;

};
//bool operator==(const Date& d1, const Date& d2)
//{
//	return d1._year == d2._year && d1._day == d2._day && d1._month == d2._month;
//}

/*实践：实现一个完善的日期类*/class Date
{
public:
	/*根据年月获取当月天数*/int GetMonthDay(int year, int month)
	{
		static int monthDays[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if (month == 2 && (year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
		{
			return 29;
		}
		return monthDays[month];
	}
	/*构造函数*/Date(int year = 0, int month = 1, int day = 1)
	{
		if (year >= 0 && month >= 1 && month <= 12 && day >= 1 && day <= GetMonthDay(year, month))
		{
			_year = year; _month = month; _day = day;
		}
		else cout << "date illegel" << endl;

	}
	/*拷贝构造*/Date(const Date& d)
	{
		_year = d._year; _month = d._month; _day = d._day;
	}
	/*打印日期*/void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	/*运算符重载*/
	 bool operator<(const Date& d)
	{
		return (_year < d._year)
			|| (_year <= d._year && _month < d._month)
			|| (_year <= d._year && _month <= d._month && _day < d._day);
	}
	 bool operator>(const Date& d)
	{
		return (_year > d._year)
			|| (_year >= d._year && _month > d._month)
			|| (_year >= d._year && _month >= d._month && _day > d._day);
	}
	 bool operator==(const Date& d)
	{
		return !operator<(d) && !operator<(d);
	}
	 bool operator<=(const Date& d)
	{
		//老师的写法
		//return *this <d||*this==d;
		return !(operator>(d));//return operator==(d) || operator<(d);
	}
	 bool operator>=(const Date& d)
	{
		return !(operator<(d));
	}
	 bool operator!=(const Date& d)
	{
		return !operator==(d);
	}
	 Date operator+(int day)//循环
	{
	    Date ret(*this);
		ret._day += day;
		while (ret._day > GetMonthDay(ret._year, ret._month))
		{
			ret._day -= GetMonthDay(ret._year, ret._month);
			ret._month ++;

			if (ret._month == 13)
			{
				ret._month = 1;
				ret._year ++;
			}
		}
		return ret;
	  
	}
	 Date& operator+=(int day)
	 {
		 _day += day;
		 while (_day > GetMonthDay(_year, _month))
		 {
			_day -= GetMonthDay(_year, _month);
			++_month;

			 if (_month == 13)
			 {
				 _month = 1;
				++ _year;
			 }
		 }
		 return *this;
	 }
	 //Date& operator+=(int day)//递归实现(本来要写+号发现递归暂时不能避免元日期的改变索性变成+=)
	 //{
		// int monthd = GetMonthDay(_year, _month);
		// if (_day + day <= monthd)
		// {
		//	 _day += day;
		//	 return *this;
		// }
		// else
		// {
		//	 _month++;
		//	 if (_month == 13)
		//	 {
		//		 _year++;
		//		 _month = 1;
		//	 }
		//	 return operator+=(day - monthd);
		// }
	 //}
	 //下节课继续
	 Date operator-(int day);
	 Date& operator-=(int day);
	 Date& operator++(int day);
	 Date& operator--(int day);
	 int  operator-(const Date&d);

private:
	int _year;
	int _month;
	int _day;
protected:

};

//【函数声明】
void Test1();void Test2();void Test3();
void datepratest1(DatePra a);void datepratest2(DatePra& a);

//【主函数】
int main()
{
	//Test1();
	//Test2();
	Test3();

	cout << "****主函数结束****" << endl;
	return 0;
}

//【函数定义】

/*测试用例*/void Test1()
{
	printf("****测试用例开始****\n");
	Person p1, p2;//类的实例化
	char p1name[] = "Yang";
	char p1password[] = "123456";
	char p2name[] = "Yan";
	char p2password[] = "12345";
	p1.InfoInput(p1name, 30, p1password);
	p1.Print();
	p2.InfoInput(p2name, 29, p2password);
	p2.Print(); 
	printf("****测试用例结束****\n\n");
}
/*类的成员函数类外声明方式*/void Stack::Empty()
{
	;
}


/*测试用例*/void Test2()
{
	printf("****测试用例开始****\n");
	//构造函数使用
	DatePra d1(2025, 4, 23);
	d1.Print();
	DatePra d2;//不传参则不加括号
	d2.Print();

	DatePra d3(d1);
	DatePra d4 = d1;
	d3.Print();
	d4.Print();
	datepratest1(d4);
	datepratest2(d4);
	if (d1 == d3)
		cout << "d1==d3" << endl;
	else cout << "d1!=d3" << endl;
	DatePra d5(2025, 4, 24);
	d5.Print();
	if (d1 > d5)
		cout << "d1>d5" << endl;
	else cout << "d1!>d5" << endl;
	if (d1 < d5)
		cout << "d1<d5" << endl;
	else cout << "d1!<d5" << endl;
	printf("****测试用例结束****\n\n");
}
/*类的传参*/void datepratest1(DatePra a)
{
	a.Print();
}
/*类的传引用*/void datepratest2(DatePra& a)
{
	a.Print();
}

/*测试用例*/void Test3()
{
	printf("****测试用例开始****\n");
	Date d1;d1.Print();
	Date d2(2024,2,23);d2.Print();
	Date d3(2025,4,23);d3.Print();
	//比较运算符
	cout << "d2<d3  :" << (d2 < d3) << endl;
	cout << "d2>d3  :" << (d2 > d3) << endl;
	cout << "d2=d3  :" << (d2 == d3) << endl;
	cout << "d2<=d3 :" << (d2 <= d3) << endl;
	cout << "d2>=d3 :" << (d2 >= d3) << endl;
	cout << "d2!=d3 :" << (d2 != d3) << endl;
	//加减运算符
	Date d4=d2 + 10;d4.Print();
	Date d5=d3 + 10;d5.Print();
	(d2 += 10)+=5; d2.Print();//在实现加等减等 等在原值上运算结果赋给原值的运算符重载返回值应该以引用的方式返回
	/*d2 - 10;
	d2 -= 10;
	d3 - d2;*/
	printf("****测试用例结束****\n\n");
}

//【笔记】

//【入门】3.类和对象(2)
//面向对象:有三大特性 封装、继承、多态
//类和对象
		//类的封装
			//类通过封装实现成员按访问限定符权限访问
			//public公有|private私有|ptrotected保护
			//struct的成员默认为公有 class的成员默认为私有
		//声明和定义的区别
			//声明： 声明是一种承诺，承诺一件事情，但没有落地
			//定义：定义是吧承诺的事情实施
		//类的实例化：类的实例化相当于定义出类的成员变量，也可以理解为定义了结构体，在函数中生成结构体类型的变量
			//类的成员函数可以类内声明、类外定义，定义时用::说明是属于类的
			//类实例化的对象中只存储成员变量不存储成员函数，因为无论类实例化出多少个对象，所有对象调用的成员函数都是同一个成员函数
			//计算类的对象的大小时按内存对齐规则只计算成员变量
			//【特殊】没有成员变量的类大小是1，因为开空间是为了占位表示对象存在，不然对象指针无法指向明确位置
		//类成员函数的隐含指针
			//类的成员函数在定义时包含一个隐含的this指针 (类名*this)，该指针存在栈上，因为它是一个形参（特殊：vs下是存在ecx寄存器）
			//所以在成员函数内使用成员变量可以直接写成员变量名，无需再指向，自动指向调用对象的成员变量	
//六种默认成员函数：默认构造函数用户不定义，编译器会自动生成默认。
	//【默认1“构造函数”】：是对象在构造时调用的函数，这个函数完成初始化工作
		//无返回值，函数名和类名相同//构造函数支持重载//实例化时会自动调用
		//如果没创建构造函数，编译器会自动生成一个隐式的构造函数，默认不传参、一旦用户定义显示构造函数，那么默认无参的构造函数不会生成
		//默认生成的构造函数针对内置类型成员变量不处理|针对自定义类的成员变量调用该类的构造函数初始化
		//自定义的构造函数可以利用缺省值来实现一个函数既能不带参构造、也可以带参构造
		//无参构造函数和全缺省构造函数只能有一种，虽然构成重载但是使用时会存在函数指向不明确（无参、全缺省、不写都认为是默认构造函数）
	//【默认2“析构函数”】：对象声明周期结束时自动调用的函数，完成对象内的【资源清理】工作，并非对对象的销毁
		//析构函数命名方式时~类名
		//主要清理对象内开辟的动态内存空间、多个对象的析构顺序是后进先出

//【入门】4.类和对象(3)
//六种默认成员函数：默认构造函数用户不定义，编译器会自动生成默认
	//【默认2“析构函数”】：对象声明周期结束时自动调用的函数，完成对象内的【资源清理】工作，并非对对象的销毁
			//无参数无返回值类型。一个类只能有一个析构函数。若未显式定义，系统会自动生成默认的析构函数。
			//默认析构函数原理和构造函数类似，类成员内置类型的不做处理、自定义类的调用该类的析构执行
			//如果类的实例化时开辟了动态内存空间，那么就需要自行定义析构函数进行处理，否则使用系统默认的析构函数
	//【默认3“拷贝构造”】：类的示例化时，复制另一个对象  "类名 对象名（类名&被拷贝对象名）"
		//拷贝构造必须用引用、且不能重载|可以理解为构造函数的一种重载
		//【额外】传参可以理解为一种拷贝构造
		// 尾巴...下节课继续
	//【默认4“运算符重载”】：增强程序可读性，是具有特殊函数名的函数，具有返回值、变量、函数名、参数列表
		//关键字 operator后面接重载运算符号 ：返回值类型 operator操作符(参数列表)
		//在成员函数中比较实际是“调用该运算符重载函数的对象”和“传递的被比较对象的引用”进行比较
		//能重载的必须是类类型，5个运算符不能重载（1..*  2.:: 3.sizeof 4.?: 5..）
		// 尾巴...下节课继续
//实现一个完善的日期类
	//关于运算符重载函数的内敛与否 
		//内联是建议，编译器会根据实际情况决定是否内联函数。
		//对于简单的运算符重载函数，可以考虑显式声明为inline，但对于复杂函数，建议让编译器自行优化。
	//是否需要重载一个运算符，看得是这个运算符是否对这个类有意义
	//在写+=这类运算符重载时之所以返回采用引用返回Date& 而不是直接返回Date,
	//是因为返回时引用返回返回的还是原来被操作的值，直接返回返回的是*this所对应的date的副本，在链式操作时会出问题。


